<!DOCTYPE html>
<html>
<head>
    

    

    



    <meta charset="utf-8">
    
    
    
    <title>zookeeper | 尼古拉斯-鱼丸博客 | 喝酒、吃肉、不赌</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    
    <meta name="theme-color" content="#3F51B5">
    
    
    <meta name="keywords" content="zookeeper">
    <meta name="description" content="什么是Zookeeper? &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ZooKeeper 是一个为分布式应用所设计的分布的、开源的协调服务。分布式的应用可以建立在同步配置管理、选举、分布式锁、分组和命名等服务的更高级别的实现的基础之上。 ZooKeeper 意欲设计一个易于编程的环境，它的文件系统使用我们所熟悉的目录树结构。 ZooKeeper 使用 Java 所编写，但是支持 Jav">
<meta name="keywords" content="zookeeper">
<meta property="og:type" content="article">
<meta property="og:title" content="zookeeper">
<meta property="og:url" content="http://fish_08.oschina.io/2017/07/06/zookeeper/index.html">
<meta property="og:site_name" content="尼古拉斯-鱼丸博客">
<meta property="og:description" content="什么是Zookeeper? &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ZooKeeper 是一个为分布式应用所设计的分布的、开源的协调服务。分布式的应用可以建立在同步配置管理、选举、分布式锁、分组和命名等服务的更高级别的实现的基础之上。 ZooKeeper 意欲设计一个易于编程的环境，它的文件系统使用我们所熟悉的目录树结构。 ZooKeeper 使用 Java 所编写，但是支持 Jav">
<meta property="og:image" content="http://fish_08.oschina.io/img/zookeeper/zknode.png">
<meta property="og:image" content="http://fish_08.oschina.io/img/zookeeper/zhucezhongxin.png">
<meta property="og:image" content="http://fish_08.oschina.io/img/zookeeper/jiantingpeizhi.png">
<meta property="og:image" content="http://fish_08.oschina.io/img/zookeeper/zkyuanli.png">
<meta property="og:updated_time" content="2017-07-07T06:43:07.753Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="zookeeper">
<meta name="twitter:description" content="什么是Zookeeper? &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ZooKeeper 是一个为分布式应用所设计的分布的、开源的协调服务。分布式的应用可以建立在同步配置管理、选举、分布式锁、分组和命名等服务的更高级别的实现的基础之上。 ZooKeeper 意欲设计一个易于编程的环境，它的文件系统使用我们所熟悉的目录树结构。 ZooKeeper 使用 Java 所编写，但是支持 Jav">
<meta name="twitter:image" content="http://fish_08.oschina.io/img/zookeeper/zknode.png">
    
        <link rel="alternative" href="/atom.xml" title="尼古拉斯-鱼丸博客" type="application/atom+xml">
    
    <link rel="shortcut icon" href="/favicon.ico">
    <link rel="stylesheet" href="/css/style.css?v=1.6.7">
    <script>window.lazyScripts=[]</script>
</head>

<body>
    <div id="loading" class="active"></div>

    <aside id="menu" class="hide" >
  <div class="inner flex-row-vertical">
    <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menu-off">
        <i class="icon icon-lg icon-close"></i>
    </a>
    <div class="brand-wrap">
      <div class="brand">
        <a href="/" class="avatar waves-effect waves-circle waves-light">
          <img src="/img/avatar.jpg">
        </a>
        <hgroup class="introduce">
          <h5 class="nickname">于亮</h5>
          <a href="mailto:136214289@qq.com" title="136214289@qq.com" class="mail">136214289@qq.com</a>
        </hgroup>
      </div>
    </div>
    <div class="scroll-wrap flex-col">
      <ul class="nav">
        
            <li class="waves-block waves-effect">
              <a href="/"  >
                <i class="icon icon-lg icon-home"></i>
                主页
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/archives"  >
                <i class="icon icon-lg icon-archives"></i>
                文档
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/tags"  >
                <i class="icon icon-lg icon-tags"></i>
                标签
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="http://git.oschina.net/fish_08" target="_blank" >
                <i class="icon icon-lg icon-github"></i>
                Github
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="http://weibo.com/2837335591/profile?rightmod=1&wvr=6&mod=personinfo" target="_blank" >
                <i class="icon icon-lg icon-weibo"></i>
                Weibo
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/custom"  >
                <i class="icon icon-lg icon-link"></i>
                测试
              </a>
            </li>
        
      </ul>
    </div>
  </div>
</aside>

    <main id="main">
        <header class="top-header" id="header">
    <div class="flex-row">
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light on" id="menu-toggle">
          <i class="icon icon-lg icon-navicon"></i>
        </a>
        <div class="flex-col header-title ellipsis">zookeeper</div>
        
        <div class="search-wrap" id="search-wrap">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="back">
                <i class="icon icon-lg icon-chevron-left"></i>
            </a>
            <input type="text" id="key" class="search-input" autocomplete="off" placeholder="输入感兴趣的关键字">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="search">
                <i class="icon icon-lg icon-search"></i>
            </a>
        </div>
        
        
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menuShare">
            <i class="icon icon-lg icon-share-alt"></i>
        </a>
        
    </div>
</header>
<header class="content-header post-header">

    <div class="container fade-scale">
        <h1 class="title">zookeeper</h1>
        <h5 class="subtitle">
            
                <time datetime="2017-07-06T08:39:43.000Z" itemprop="datePublished" class="page-time">
  2017-07-06
</time>


            
        </h5>
    </div>

    

</header>


<div class="container body-wrap">
    
    <aside class="post-widget">
        <nav class="post-toc-wrap" id="post-toc">
            <h4>TOC</h4>
            <ol class="post-toc"><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#什么是Zookeeper"><span class="post-toc-number">1.</span> <span class="post-toc-text">什么是Zookeeper?</span></a></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#zookeeper数据结构？"><span class="post-toc-number">2.</span> <span class="post-toc-text">zookeeper数据结构？</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#zk目录树结构"><span class="post-toc-number">2.1.</span> <span class="post-toc-text">zk目录树结构</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#zk节点"><span class="post-toc-number">2.2.</span> <span class="post-toc-text">zk节点</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#zookeeper使用场景？"><span class="post-toc-number">3.</span> <span class="post-toc-text">zookeeper使用场景？</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#命名服务"><span class="post-toc-number">3.1.</span> <span class="post-toc-text">命名服务</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#数据发布与订阅（配置中心）"><span class="post-toc-number">3.2.</span> <span class="post-toc-text">数据发布与订阅（配置中心）</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#GroupMembers-集群管理"><span class="post-toc-number">3.3.</span> <span class="post-toc-text">GroupMembers 集群管理</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#分布通知-协调"><span class="post-toc-number">3.4.</span> <span class="post-toc-text">分布通知/协调</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#分布式锁"><span class="post-toc-number">3.5.</span> <span class="post-toc-text">分布式锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#分布式队列"><span class="post-toc-number">3.6.</span> <span class="post-toc-text">分布式队列</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#负载均衡"><span class="post-toc-number">3.7.</span> <span class="post-toc-text">负载均衡</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#zookeepr原理"><span class="post-toc-number">4.</span> <span class="post-toc-text">zookeepr原理</span></a></li></ol>
        </nav>
    </aside>
    
<article id="post-zookeeper"
  class="post-article article-type-post fade" itemprop="blogPost">

    <div class="post-card">
        <h1 class="post-card-title">zookeeper</h1>
        <div class="post-meta">
            <time class="post-time" title="2017年07月06日 16:39" datetime="2017-07-06T08:39:43.000Z"  itemprop="datePublished">2017-07-06</time>

            


            
<span id="busuanzi_container_page_pv" title="文章总阅读量" style='display:none'>
    <i class="icon icon-eye icon-pr"></i><span id="busuanzi_value_page_pv"></span>
</span>


            

        </div>
        <div class="post-content" id="post-content" itemprop="postContent">
            <h3 id="什么是Zookeeper"><a href="#什么是Zookeeper" class="headerlink" title="什么是Zookeeper?"></a>什么是Zookeeper?</h3><p> &nbsp; &nbsp; &nbsp; &nbsp;ZooKeeper 是一个为分布式应用所设计的分布的、开源的协调服务。分布式的应用可以建立在同步配置管理、选举、分布式锁、分组和命名等服务的更高级别的实现的基础之上。 ZooKeeper 意欲设计一个易于编程的环境，它的文件系统使用我们所熟悉的目录树结构。 ZooKeeper 使用 Java 所编写，但是支持 Java 和 C 两种编程语言。协调服务⾮常容易出错，但是却很难恢复正常，例如，协调服务很容易处于竞争状态以⾄于出现死锁。设计 ZooKeeper 的目的是为了减轻分布式应⽤程序所承担的协调任务，借助于zookeeper服务开发出高可靠的分布式协同程序。<br><strong>为什么使用ZooKeeper</strong><br> &nbsp; &nbsp; &nbsp; &nbsp;我们知道要写一个分布式应用是非常困难的，主要原因就是局部故障。一个消息通过网络在两个节点之间传递时，网络如果发生故障，发送方并不知道接收方是否接收到了这个消息。他可能在网络故障迁就收到了此消息，也坑没有收到，又或者可能接收方的进程死了。发送方了解情况的唯一方法就是再次连接发送方，并向他进行询问。这就是局部故障：根本不知道操作是否失败。因此，大部分分布式应用需要一个主控、协调控制器来管理物理分布的子进程。目前，大部分应用需要开发私有的协调程序，缺乏一个通用的机制。协调程序的反复编写浪费，且难以形成通用、伸缩性好的协调器。协调服务非常容易出错，并很难从故障中恢复。例如：协调服务很容易处于竞态1甚至死锁2。Zookeeper的设计目的，是为了减轻分布式应用程序所承担的协调任务。<br>Zookeeper并不能阻止局部故障的发生，因为它们的本质是分布式系统。他当然也不会隐藏局部故障。ZooKeeper的目的就是提供一些工具集，用来建立安全处理局部故障的分布式应用。<br>ZooKeeper是一个分布式小文件系统，并且被设计为高可用性。通过选举算法和集群复制可以避免单点故障3，由于是文件系统，所以即使所有的ZooKeeper节点全部挂掉，数据也不会丢失，重启服务器之后，数据即可恢复。另外ZooKeeper的节点更新是原子的，也就是说更新不是成功就是失败。通过版本号，ZooKeeper实现了更新的乐观锁4，当版本号不相符时，则表示待更新的节点已经被其他客户端提前更新了，而当前的整个更新操作将全部失败。当然所有的一切ZooKeeper已经为开发者提供了保障，我们需要做的只是调用API。与此同时，随着分布式应用的的不断深入，需要对集群管理逐步透明化监控集群和作业状态，可以充分利ZK的独有特性。</p>
<h3 id="zookeeper数据结构？"><a href="#zookeeper数据结构？" class="headerlink" title="zookeeper数据结构？"></a>zookeeper数据结构？</h3><h4 id="zk目录树结构"><a href="#zk目录树结构" class="headerlink" title="zk目录树结构"></a>zk目录树结构</h4><p>  &nbsp; &nbsp; &nbsp; &nbsp; zk文件系统类似于我们目录树结构，提供的命名空间与标准的⽂件系统非常相似。一个名称是由通过斜线分隔开的路径名序列所组成的。 ZooKeeper中的每一个节点是都通过路径来识别。<br>  <img src="/img/zookeeper/zknode.png" alt="zk目录树结构"><br>  注意:ZNODE文件系统的区别  ZK不存在文件和文件夹的概念.所有的ZNODE都是可以存储少量数据.</p>
<h4 id="zk节点"><a href="#zk节点" class="headerlink" title="zk节点"></a>zk节点</h4><p> zookeeper=文件系统+通知机制。<br> &nbsp; &nbsp; &nbsp; &nbsp;ZooKeeper的节点是通过像树一样的结构来进行维护的，并且每一个节点通过路径来标识以及访问。除此之外，每一个节点还拥有自身的一些信息，包括：数据、数据长度、创建时间、修改时间等等。从这样⼀类既含有数据，又作为路径表标⽰的节点的特点中，可以看出， ZooKeeper的节点既可以被看做是一个文件，又可以被看做是一个目录，它同时具有两者的特点。为了便于表达，今后将使用Znode来表所讨论的ZooKeeper节点。<br>具体地说，Znode维护着数据、 ACL（ access control list，访问控制列表）、时间戳等交换版本号等数据结构，它通过对这些数据的管理来让缓存生效并且令协调更新。每当Znode中的数据更新后它所维护的版本号将增加，这非常类似于数据库中计数器时间戳的操作方式。</p>
<p>  &nbsp; &nbsp;&nbsp; &nbsp;另外Znode还具有原⼦性操作的特点：命名空间中，每⼀个Znode的数据将被原子地读写。读操作将读取与Znode相关的所有数据，写操作将替换掉所有的数据。除此之外，每一个节点都有一个访问控制列表，这个访问控制列表规定了用户操作的权限。ZooKeeper中同样存在临时节点。这些节点与session同时存在，当session生命周期结束，这些临时节点也将被删除。临时节点在某些场合也发挥着非常重要的作用。<br>ZooKeeper 节点是有生命周期的，这取决于节点的类型。在 ZooKeeper 中，节点类型可以分为持久节点（PERSISTENT ）、临时节点（EPHEMERAL），以及时序节点（SEQUENTIAL ），具体在节点创建过程中，一般是组合使用，可以生成以下 4 种节点类型。</p>
<p> <strong>持久节点（PERSISTENT）</strong><br>   &nbsp; &nbsp;&nbsp; &nbsp;持久节点，是指在节点创建后，就一直存在，直到有删除操作来主动清除这个节点——不会因为创建该节点的客户端会话失效而消失。</p>
<p> <strong> 持久顺序节点（PERSISTENT_SEQUENTIAL）</strong><br>  &nbsp; &nbsp;&nbsp; &nbsp;这类节点的基本特性和上面的节点类型是一致的。额外的特性是，在ZK中，每个父节点会为他的第一级子节点维护一份时序，会记录每个子节点创建的先后顺序。基于这个特性，在创建子节点的时候，可以设置这个属性，那么在创建节点过程中，ZK会自动为给定节点名加上一个数字后缀，作为新的节点名。这个数字后缀的范围是整型的最大值。</p>
<p> <strong> 临时节点（EPHEMERAL）</strong><br>  &nbsp; &nbsp;&nbsp; &nbsp;和持久节点不同的是，临时节点的生命周期和客户端会话绑定。也就是说，如果客户端会话失效，那么这个节点就会自动被清除掉。注意，这里提到的是会话失效，而非连接断开。另外，在临时节点下面不能创建子节点。</p>
<p> <strong> 临时顺序节点（EPHEMERAL_SEQUENTIAL）</strong><br>  &nbsp; &nbsp;&nbsp; &nbsp;这类节点的基本特性和上面的节点类型是一致的。额外的特性是，在ZK中，每个父节点会为他的第一级子节点维护一份时序，会记录每个子节点创建的先后顺序。基于这个特性，在创建子节点的时候，可以设置这个属性，那么在创建节点过程中，ZK会自动为给定节点名加上一个数字后缀，作为新的节点名。这个数字后缀的范围是整型的最大值。<br>临时节点（EPHEMERAL）和持久节点不同的是，临时节点的生命周期和客户端会话绑定。也就是说，如果客户端会话失效，那么这个节点就会自动被清除掉。注意，这里提到的是会话失效，而非连接断开。另外，在临时节点下面不能创建子节点。临时顺序节点（EPHEMERAL_SEQUENTIAL）<br>分布式锁<br>第一步：客户端调用create()方法创建“<em>locknode</em>/guid-lock-”节点，需要注意的是，这里节点的创建类型设置EPHEMERAL_SEQUENTIAL。<br>第二步：客户端调用getChildren(“<em>locknode</em>”)方法来获取所有已经创建的子节点，注意，这里不注册任何Watcher。<br>第三步：客户端获取到所有子节点path之后，如果发现自己在步骤1中创建的节点序号最小，那么就认为这个客户端获得了锁。<br>如果在步骤3中发现自己并非所有子节点中最小的，说明自己还没有获取到锁。此时客户端需要找到比自己小的那个节点，然后对其调用exist()方法，同时<br>注册事件监听。之后当这个被关注的节点被移除了，客户端会收到相应的通知。这个时候客户端需要再次调用getChildren(“<em>locknode</em>”)方法来获取所有已经创建的子节点，确保自己确实是最小的节点了，然后进入步骤3。</p>
<p> <strong>监测</strong><br>    客户端可以监测znode节点的变化。Znode节点的变化触发相应的事件，然后清除对该节点的监测。当监测一个znode节点时候，Zookeeper会发送通知给监测节点。</p>
<p> <strong>Zookeeper ACL控制</strong><br>   &nbsp; &nbsp; &nbsp; &nbsp;传统的文件系统中，ACL分为两个维度，一个是属组，一个是权限，子目录/文件默认继承父目录的ACL。而在Zookeeper中，znode的ACL是没有继承关系的，是独立控制的。Zookeeper的ACL，可以从三个维度来理解：一是scheme; 二是user; 三是permission，通常表示为scheme:id:permissions, 下面从这三个方面分别来介绍:<br>    <strong>scheme</strong>: scheme对应于采用哪种方案来进行权限管理，zookeeper实现了一个pluggable的ACL方案，可以通过扩展scheme，来扩展ACL的机制。zookeeper-3.4.4缺省支持下面几种scheme: world: 它下面只有一个id, 叫anyone, world:anyone代表任何人，zookeeper中对所有人有权限的结点就是属于world:anyone的 auth: 它不需要id, 只要是通过authentication的user都有权限（zookeeper支持通过kerberos来进行authencation, 也支持username/password形式的authentication) digest: 它对应的id为username:BASE64(SHA1(password))，它需要先通过username:password形式的authentication ip: 它对应的id为客户机的IP地址，设置的时候可以设置一个ip段，比如ip:192.168.1.0/16, 表示匹配前16个bit的IP段 super: 在这种scheme情况下，对应的id拥有超级权限，可以做任何事情(cdrwa) 。<br>    <strong>id</strong>: id与scheme是紧密相关的，具体的情况在上面介绍scheme的过程都已介绍，这里不再赘述。<br>    <strong>permission</strong>: zookeeper目前支持下面一些权限： CREATE(c): 创建权限，可以在在当前node下创建child node DELETE(d): 删除权限，可以删除当前的node READ(r): 读权限，可以获取当前node的数据，可以list当前node所有的child nodes WRITE(w): 写权限，可以向当前node写数据 ADMIN(a): 管理权限，可以设置当前node的permission 实现 如前所述，在zookeeper中提供了一种pluggable的ACL机制。具体来说就是每种scheme对应于一种ACL机制，可以通过扩展scheme来扩展ACL的机制。在具体的实现中，每种scheme对应一种AuthenticationProvider。每种AuthenticationProvider实现了当前机制下authentication的检查，通过了authentication的检查，然后再进行统一的permission检查，如此便实现了ACL。所有的AuthenticationProvider都注册在ProviderRegistry中，新扩展的AuthenticationProvider可以通过配置注册到ProviderRegistry中去。下面是实施检查的具体实现.</p>
<p>   ZooKeeper的安装模式分为三种，分别为：单机模式（ stand-alone）、集群模式和集群伪分布模式。为了获得可靠的zk服务，用户应当在集群上部署zk，zk服务启动奇数台服务，这样保证N-1/2服务故障了，zk服务还是可用的。</p>
<h3 id="zookeeper使用场景？"><a href="#zookeeper使用场景？" class="headerlink" title="zookeeper使用场景？"></a>zookeeper使用场景？</h3><p>  ZooKeeper是一个高可用的分布式数据管理与系统协调框架。基于对Paxos算法的实现，使该框架保证了分布式环境中数据的强一致性，也正是基 于这样的特性，使得zookeeper能够应用于很多场景</p>
<h4 id="命名服务"><a href="#命名服务" class="headerlink" title="命名服务"></a>命名服务</h4><p>命名服务是指通过指定的名字来获取资源或者服务的地址，提供者的信息。利用Zookeeper很容易创建一个全局的路径，而这个路径就可以作为一个名字，它可以指向集群中的集群，提供的服务的地址，远程对象等。简单来说使用Zookeeper做命名服务就是用路径作为名字，路径上的数据就是其名字指向的实体。<br>阿里巴巴集团开源的分布式服务框架Dubbo中使用ZooKeeper来作为其命名服务，维护全局的服务地址列表。在Dubbo实现中：<br>服务提供者在启动的时候，向ZK上的指定节点/dubbo/${serviceName}/providers目录下写入自己的URL地址，这个操作就完成了服务的发布。<br>服务消费者启动的时候，订阅/dubbo/{serviceName}/providers目录下的提供者URL地址， 并向/dubbo/{serviceName} /consumers目录下写入自己的URL地址。<br>注意，所有向ZK上注册的地址都是临时节点，这样就能够保证服务提供者和消费者能够自动感应资源的变化。<br>另外，Dubbo还有针对服务粒度的监控，方法是订阅/dubbo/{serviceName}目录下所有提供者和消费者的信息。<br> <figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/zookeeper/zhucezhongxin.png" alt="注册中心" title="">
                </div>
                <div class="image-caption">注册中心</div>
            </figure></p>
<h4 id="数据发布与订阅（配置中心）"><a href="#数据发布与订阅（配置中心）" class="headerlink" title="数据发布与订阅（配置中心）"></a>数据发布与订阅（配置中心）</h4><p>发布与订阅模型，即所谓的配置中心，顾名思义就是发布者将数据发布到ZK节点上，供订阅者动态获取数据，实现配置信息的集中式管理和动态更新。例如全局的配置信息，服务式服务框架的服务地址列表等就非常适合使用。<br>应用中用到的一些配置信息放到ZK上进行集中管理。这类场景通常是这样：应用在启动的时候会主动来获取一次配置，同时，在节点上注册一个Watcher，这样一来，以后每次配置有更新的时候，都会实时通知到订阅的客户端，从来达到获取最新配置信息的目的。<br>分布式搜索服务中，索引的元信息和服务器集群机器的节点状态存放在ZK的一些指定节点，供各个客户端订阅使用。<br>分布式日志收集系统。这个系统的核心工作是收集分布在不同机器的日志。收集器通常是按照应用来分配收集任务单元，因此需要在ZK上创建一个以应用名作为path的节点P，并将这个应用的所有机器ip，以子节点的形式注册到节点P上，这样一来就能够实现机器变动的时候，能够实时通知到收集器调整任务分配。<br>系统中有些信息需要动态获取，并且还会存在人工手动去修改这个信息的发问。通常是暴露出接口，例如JMX接口，来获取一些运行时的信息。引入ZK之后，就不用自己实现一套方案了，只要将这些信息存放到指定的ZK节点上即可。<br>注意：在上面提到的应用场景中，有个默认前提是：数据量很小，但是数据更新可能会比较快的场景<br>  <img src="/img/zookeeper/jiantingpeizhi.png" alt="监听配置"></p>
<h4 id="GroupMembers-集群管理"><a href="#GroupMembers-集群管理" class="headerlink" title="GroupMembers 集群管理"></a>GroupMembers 集群管理</h4><p>集群机器监控：这通常用于那种对集群中机器状态，机器在线率有较高要求的场景，能够快速对集群中机器变化作出响应。这样的场景中，往往有一个监控系统，实时检测集群机器是否存活。过去的做法通常是：监控系统通过某种手段（比如ping）定时检测每个机器，或者每个机器自己定时向监控系统汇报“我还活着”。 这种做法可行，但是存在两个比较明显的问题：<br>集群中机器有变动的时候，牵连修改的东西比较多。<br>有一定的延时。<br>利用ZooKeeper有两个特性，就可以实时另一种集群机器存活性监控系统：<br>客户端在节点 x 上注册一个Watcher，那么如果 x?的子节点变化了，会通知该客户端。<br>创建EPHEMERAL类型的节点，一旦客户端和服务器的会话结束或过期，那么该节点就会消失。<br>例如，监控系统在 /clusterServers 节点上注册一个Watcher，以后每动态加机器，那么就往 /clusterServers 下创建一个 EPHEMERAL类型的节点：/clusterServers/{hostname}. 这样，监控系统就能够实时知道机器的增减情况，至于后续处理就是监控系统的业务了。</p>
<p>Master选举则是zookeeper中最为经典的应用场景了。<br>在分布式环境中，相同的业务应用分布在不同的机器上，有些业务逻辑（例如一些耗时的计算，网络I/O处理），往往只需要让整个集群中的某一台机器进行执行，其余机器可以共享这个结果，这样可以大大减少重复劳动，提高性能，于是这个master选举便是这种场景下的碰到的主要问题。<br>利用ZooKeeper的强一致性，能够保证在分布式高并发情况下节点创建的全局唯一性，即：同时有多个客户端请求创建 /currentMaster 节点，最终一定只有一个客户端请求能够创建成功。利用这个特性，就能很轻易的在分布式环境中进行集群选取了。<br>另外，这种场景演化一下，就是动态Master选举。这就要用到?EPHEMERAL_SEQUENTIAL类型节点的特性了。<br>上文中提到，所有客户端创建请求，最终只有一个能够创建成功。在这里稍微变化下，就是允许所有请求都能够创建成功，但是得有个创建顺序，于是所有的请求最终在ZK上创建结果的一种可能情况是这样： /currentMaster/{sessionId}-1 ,?/currentMaster/{sessionId}-2 ,?/currentMaster/{sessionId}-3 ….. 每次选取序列号最小的那个机器作为Master，如果这个机器挂了，由于他创建的节点会马上小时，那么之后最小的那个机器就是Master了。</p>
<h4 id="分布通知-协调"><a href="#分布通知-协调" class="headerlink" title="分布通知/协调"></a>分布通知/协调</h4><p>ZooKeeper 中特有watcher注册与异步通知机制，能够很好的实现分布式环境下不同系统之间的通知与协调，实现对数据变更的实时处理。使用方法通常是不同系统都对 ZK上同一个znode进行注册，监听znode的变化（包括znode本身内容及子节点的），其中一个系统update了znode，那么另一个系统能 够收到通知，并作出相应处理。</p>
<ol>
<li>另一种心跳检测机制：检测系统和被检测系统之间并不直接关联起来，而是通过zk上某个节点关联，大大减少系统耦合。</li>
<li>另一种系统调度模式：某系统有控制台和推送系统两部分组成，控制台的职责是控制推送系统进行相应的推送工作。管理人员在控制台作的一些操作，实际上是修改 了ZK上某些节点的状态，而zk就把这些变化通知给他们注册Watcher的客户端，即推送系统，于是，作出相应的推送任务。</li>
<li>另一种工作汇报模式：一些类似于任务分发系统，子任务启动后，到zk来注册一个临时节点，并且定时将自己的进度进行汇报（将进度写回这个临时节点），这样任务管理者就能够实时知道任务进度。<br>总之，使用zookeeper来进行分布式通知和协调能够大大降低系统之间的耦合。</li>
</ol>
<h4 id="分布式锁"><a href="#分布式锁" class="headerlink" title="分布式锁"></a>分布式锁</h4><p>分布式锁，这个主要得益于ZooKeeper为我们保证了数据的强一致性，即用户只要完全相信每时每刻，zk集群中任意节点（一个zk server）上的相同znode的数据是一定是相同的。锁服务可以分为两类，一个是保持独占，另一个是控制时序。<br>保持独占，就是所有试图来获取这个锁的客户端，最终只有一个可以成功获得这把锁。通常的做法是把zk上的一个znode看作是一把锁，通过create znode的方式来实现。所有客户端都去创建 /distribute_lock 节点，最终成功创建的那个客户端也即拥有了这把锁。<br>控制时序，就是所有视图来获取这个锁的客户端，最终都是会被安排执行，只是有个全局时序了。做法和上面基本类似，只是这里 /distribute_lock 已经预先存在，客户端在它下面创建临时有序节点（这个可以通过节点的属性控制：CreateMode.EPHEMERAL_SEQUENTIAL来指定）。Zk的父节点（/distribute_lock）维持一份sequence,保证子节点创建的时序性，从而也形成了每个客户端的全局时序。</p>
<h4 id="分布式队列"><a href="#分布式队列" class="headerlink" title="分布式队列"></a>分布式队列</h4><p>队列方面，简单地讲有两种，一种是常规的先进先出队列，另一种是要等到队列成员聚齐之后的才统一按序执行。对于第一种先进先出队列，和分布式锁服务中的控制时序场景基本原理一致，这里不再赘述。<br>第二种队列其实是在FIFO队列的基础上作了一个增强。通常可以在 /queue 这个znode下预先建立一个/queue/num 节点，并且赋值为n（或者直接给/queue赋值n），表示队列大小，之后每次有队列成员加入后，就判断下是否已经到达队列大小，决定是否可以开始执行了。这种用法的典型场景是，分布式环境中，一个大任务Task A，需要在很多子任务完成（或条件就绪）情况下才能进行。这个时候，凡是其中一个子任务完成（就绪），那么就去 /taskList 下建立自己的临时时序节点（CreateMode.EPHEMERAL_SEQUENTIAL），当 /taskList 发现自己下面的子节点满足指定个数，就可以进行下一步按序进行处理了。</p>
<h4 id="负载均衡"><a href="#负载均衡" class="headerlink" title="负载均衡"></a>负载均衡</h4><p>这里说的负载均衡是指软负载均衡。在分布式环境中，为了保证高可用性，通常同一个应用或同一个服务的提供方都会部署多份，达到对等服务。而消费者就须要在这些对等的服务器中选择一个来执行相关的业务逻辑，其中比较典型的是消息中间件中的生产者，消费者负载均衡。<br>消息中间件中发布者和订阅者的负载均衡，linkedin开源的KafkaMQ和阿里开源的metaq都是通过zookeeper来做到生产者、消费者的负载均衡。这里以metaq为例如讲下：<br>生产者负载均衡：metaq发送消息的时候，生产者在发送消息的时候必须选择一台broker上的一个分区来发送消息，因此metaq在运行过程中，会把所有broker和对应的分区信息全部注册到ZK指定节点上，默认的策略是一个依次轮询的过程，生产者在通过ZK获取分区列表之后，会按照brokerId和partition的顺序排列组织成一个有序的分区列表，发送的时候按照从头到尾循环往复的方式选择一个分区来发送消息。</p>
<p>原文:<a href="http://www.cnblogs.com/tommyli/p/3766189.html" target="_blank" rel="external">http://www.cnblogs.com/tommyli/p/3766189.html</a></p>
<h3 id="zookeepr原理"><a href="#zookeepr原理" class="headerlink" title="zookeepr原理"></a>zookeepr原理</h3><p>  <img src="/img/zookeeper/zkyuanli.png" alt="zk原理"><br> 原文：<a href="http://blog.csdn.net/gs80140/article/details/51496925" target="_blank" rel="external">http://blog.csdn.net/gs80140/article/details/51496925</a></p>

        </div>

        <blockquote class="post-copyright">
    <div class="content">
        
<span class="post-time">
    最后更新时间：<time datetime="2017-07-07T06:43:07.753Z" itemprop="dateUpdated">2017年7月7日 14:43</time>
</span><br>


        如要转载请注明出处：<a href="/2017/07/06/zookeeper/" target="_blank" rel="external">http://fish_08.oschina.io/2017/07/06/zookeeper/</a>
    </div>
    <footer>
        <a href="http://fish_08.oschina.io">
            <img src="/img/avatar.jpg" alt="于亮">
            于亮
        </a>
    </footer>
</blockquote>

        
<div class="page-reward">
    <a id="rewardBtn" href="javascript:;" class="page-reward-btn waves-effect waves-circle waves-light">赏</a>
</div>



        <div class="post-footer">
            
	<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/zookeeper/">zookeeper</a></li></ul>


            
<div class="page-share-wrap">
    

<div class="page-share" id="pageShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://fish_08.oschina.io/2017/07/06/zookeeper/&title=《zookeeper》 — 尼古拉斯-鱼丸博客&pic=http://fish_08.oschina.io/img/avatar.jpg" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://fish_08.oschina.io/2017/07/06/zookeeper/&title=《zookeeper》 — 尼古拉斯-鱼丸博客&source=" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://fish_08.oschina.io/2017/07/06/zookeeper/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《zookeeper》 — 尼古拉斯-鱼丸博客&url=http://fish_08.oschina.io/2017/07/06/zookeeper/&via=http://fish_08.oschina.io" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://fish_08.oschina.io/2017/07/06/zookeeper/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>



    <a href="javascript:;" id="shareFab" class="page-share-fab waves-effect waves-circle">
        <i class="icon icon-share-alt icon-lg"></i>
    </a>
</div>



        </div>
    </div>

    
<nav class="post-nav flex-row flex-justify-between">
  
    <div class="waves-block waves-effect prev">
      <a href="/2017/07/06/dubbo/" id="post-prev" class="post-nav-link">
        <div class="tips"><i class="icon icon-angle-left icon-lg icon-pr"></i> Prev</div>
        <h4 class="title">dubbo</h4>
      </a>
    </div>
  

  
    <div class="waves-block waves-effect next">
      <a href="/2017/07/06/lucene/" id="post-next" class="post-nav-link">
        <div class="tips">Next <i class="icon icon-angle-right icon-lg icon-pl"></i></div>
        <h4 class="title">lucene</h4>
      </a>
    </div>
  
</nav>



    







</article>

<div id="reward" class="page-modal reward-lay">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <h3 class="reward-title">
        <i class="icon icon-quote-left"></i>
        谢谢包子~
        <i class="icon icon-quote-right"></i>
    </h3>
    <ul class="reward-items">
        
        <li>
            <img src="/img/wechat.png" title="微信打赏二维码" alt="微信打赏二维码">
            <p>微信</p>
        </li>
        

        
        <li>
            <img src="/img/alipay.png" title="支付宝打赏二维码" alt="支付宝打赏二维码">
            <p>支付宝</p>
        </li>
        
    </ul>
</div>



</div>

        <footer class="footer">
    <div class="top">
        
<p>
    <span id="busuanzi_container_site_uv" style='display:none'>
        站点总访客数：<span id="busuanzi_value_site_uv"></span>
    </span>
    <span id="busuanzi_container_site_pv" style='display:none'>
        站点总访问量：<span id="busuanzi_value_site_pv"></span>
    </span>
</p>


        <p>
            <span><a href="/atom.xml" target="_blank" class="rss" title="rss"><i class="icon icon-lg icon-rss"></i></a></span>
            <span>博客内容遵循 <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">知识共享 署名 - 非商业性 - 相同方式共享 4.0协议</a></span>
        </p>
    </div>
    <div class="bottom">
        <p>
            <span>Power by <a href="http://hexo.io/" target="_blank">Hexo</a> Theme <a href="http://fish_08.oschina.io/" target="_blank">yuliang</a></span>
            <span>尼古拉斯-鱼丸博客 &copy; 2015 - 2018</span>
        </p>
    </div>
</footer>

    </main>
    <div class="mask" id="mask"></div>
<a href="javascript:;" id="gotop" class="waves-effect waves-circle waves-light"><span class="icon icon-lg icon-chevron-up"></span></a>



<div class="global-share" id="globalShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://fish_08.oschina.io/2017/07/06/zookeeper/&title=《zookeeper》 — 尼古拉斯-鱼丸博客&pic=http://fish_08.oschina.io/img/avatar.jpg" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://fish_08.oschina.io/2017/07/06/zookeeper/&title=《zookeeper》 — 尼古拉斯-鱼丸博客&source=" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://fish_08.oschina.io/2017/07/06/zookeeper/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《zookeeper》 — 尼古拉斯-鱼丸博客&url=http://fish_08.oschina.io/2017/07/06/zookeeper/&via=http://fish_08.oschina.io" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://fish_08.oschina.io/2017/07/06/zookeeper/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>


<div class="page-modal wx-share" id="wxShare">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <p>扫一扫，分享到微信</p>
    <img src="" alt="微信分享二维码">
</div>




    <script src="//cdn.bootcss.com/node-waves/0.7.4/waves.min.js"></script>
<script>
var BLOG = { ROOT: '/', SHARE: true, REWARD: true };



</script>

<script src="/js/main.min.js?v=1.6.7"></script>


<div class="search-panel" id="search-panel">
    <ul class="search-result" id="search-result"></ul>
</div>
<template id="search-tpl">
<li class="item">
    <a href="{path}" class="waves-block waves-effect">
        <div class="title ellipsis" title="{title}">{title}</div>
        <div class="flex-row flex-middle">
            <div class="tags ellipsis">
                {tags}
            </div>
            <time class="flex-col time">{date}</time>
        </div>
    </a>
</li>
</template>

<script src="/js/search.min.js?v=1.6.7" async></script>






<script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>


</body>
</html>
